/*
 * Copyright (C) 2015 Daniel Uppenkamp
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.maurersmarbles.states;

import com.google.common.base.Preconditions;
import com.googlecode.maurersmarbles.GameLogic;
import com.googlecode.maurersmarbles.GameState;
import com.googlecode.maurersmarbles.InputEvent;
import com.googlecode.maurersmarbles.RGB;
import com.googlecode.maurersmarbles.Rectangle;
import com.googlecode.maurersmarbles.Screen;
import com.googlecode.maurersmarbles.TouchEvent;
import com.googlecode.maurersmarbles.drawables.ButtonDrawable;
import com.googlecode.maurersmarbles.drawables.Drawable;
import com.googlecode.maurersmarbles.drawables.MarbleDrawable;
import com.googlecode.maurersmarbles.drawables.RectangleDrawable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 *
 * @author Daniel Uppenkamp
 */
public class NewGameState implements PushState {

    /**
     * The NewGameState instance.
     */
    private static final NewGameState INSTANCE = new NewGameState();
    /**
     * The text for the start game button.
     */
    protected static final String BUTTON_TEXT_START_GAME = "Start Game";
    /**
     * The ratio of the screen width to the marble width/height.
     */
    protected static final float SCREEN_WIDTH_TO_MARBLE_SIZE = 0.2f;
    /**
     * The button drawable for the start game button.
     */
    protected ButtonDrawable startGameButtonDrawable;
    /**
     * The list of marble drawables.
     */
    protected List<MarbleDrawable> marbleDrawables = new ArrayList();
    /**
     * The marble that is currently selected.
     */
    protected MarbleDrawable selectedMarbleDrawable = null;

    /**
     * Creates a new NewGameState.
     */
    private NewGameState() {

        // create the button drawable
        startGameButtonDrawable = new ButtonDrawable(BUTTON_TEXT_START_GAME);

        // create the marble drawables
        for (int i = 0; i < GameLogic.NUMBER_OF_PLAYERS; i++) {
            marbleDrawables.add(new MarbleDrawable(GameLogic.getMarbleColorForPlayer(0, i)));
        }

        // select the first color by default
        selectedMarbleDrawable = marbleDrawables.get(0);

    }

    /**
     * Returns the drawables to draw on the screen.
     *
     * @param screen the screen
     * @return the drawables to draw on the screen
     */
    protected Collection<Drawable> getDrawables(Screen screen) {

        Preconditions.checkNotNull(screen, "Null screen");
        Preconditions.checkNotNull(startGameButtonDrawable, "Null start game button drawable");
        Preconditions.checkNotNull(marbleDrawables, "Null marble drawables");
        
        Collection<Drawable> drawables = new ArrayList();

        drawables.add(new RectangleDrawable(0, 0, screen.getWidth(), screen.getHeight(), RGB.WHITE, true));

        // TODO Finish the design/implementation of the drawables
        double marbleSize = screen.getWidth() * SCREEN_WIDTH_TO_MARBLE_SIZE;
        double spacingWidth = (screen.getWidth() - (marbleSize * GameLogic.NUMBER_OF_PLAYERS)) * SCREEN_WIDTH_TO_MARBLE_SIZE;
        int startX = (int) spacingWidth;
        int startY = 0;        
        for (int i = 0; i < marbleDrawables.size(); i++) {
            marbleDrawables.get(i).setRectangle(new Rectangle((int) (startX + ((marbleSize + spacingWidth) * i)), (int) startY, (int) marbleSize, (int) marbleSize));
            drawables.add(marbleDrawables.get(i));
        }
                
        int buttonWidth = (int) (screen.getWidth() * ButtonDrawable.SCREEN_WIDTH_TO_BUTTON_WIDTH);
        int buttonHeight = (int) (screen.getHeight() * ButtonDrawable.SCREEN_HEIGHT_TO_BUTTON_HEIGHT);
        startX = (int) ((screen.getWidth() - buttonWidth) / 2.0);
        // TODO Make this a constant
        startY = (int)(marbleSize + spacingWidth);
        startGameButtonDrawable.setRectangle(new Rectangle(startX, startY, buttonWidth, buttonHeight));
        drawables.add(startGameButtonDrawable);

        if (selectedMarbleDrawable != null) {
            drawables.add(new RectangleDrawable(selectedMarbleDrawable.getRectangle(), RGB.BLACK));
        }

        return drawables;

    }

    /**
     * Returns the NewGameState instance.
     *
     * @return the NewGameState instance
     */
    public static NewGameState getInstance() {
        return INSTANCE;
    }

    @Override
    public State enter(Screen screen, GameState gameState) {

        // check to see if we have a screen
        if (screen != null) {

            // get the drawables and draw them on the screen
            screen.draw(getDrawables(screen));

        }

        // return null to stay in this state
        return null;

    }

    @Override
    public State handleInputEvent(Screen screen, GameState gameState, InputEvent inputEvent) {

        Preconditions.checkNotNull(gameState, "Null game state");
        Preconditions.checkNotNull(inputEvent, "Null input event");
        Preconditions.checkNotNull(startGameButtonDrawable, "Null start game button drawable");
        Preconditions.checkNotNull(marbleDrawables, "Null marble drawables");
        
        State newState = null;

        // check to see if we have a screen
        if (screen != null) {

            // reset the button to not pressed
            startGameButtonDrawable.setPressed(false);

            if (inputEvent instanceof TouchEvent) {

                TouchEvent touchEvent = (TouchEvent) inputEvent;

                if (touchEvent.getType() == TouchEvent.TYPE_PRESSED) {
                    Rectangle rectangle = startGameButtonDrawable.getRectangle();
                    if (rectangle != null && rectangle.contains(touchEvent.getX(), touchEvent.getY())) {
                        startGameButtonDrawable.setPressed(true);
                    }
                }
                else if (touchEvent.getType() == TouchEvent.TYPE_RELEASED) {

                    // check to see if a new marble color was selected
                    for (MarbleDrawable marbleDrawable : marbleDrawables) {

                        Rectangle rectangle = marbleDrawable.getRectangle();
                        if (rectangle != null && rectangle.contains(touchEvent.getX(), touchEvent.getY())) {
                            selectedMarbleDrawable = marbleDrawable;
                            break;
                        }

                    }

                    Rectangle rectangle = startGameButtonDrawable.getRectangle();
                    if (rectangle != null && rectangle.contains(touchEvent.getX(), touchEvent.getY())) {

                        // reinitialize the game state for a new game
                        gameState.reinitialize();

                        // set the user's marble color
                        gameState.setUserMarbleColorIndex(marbleDrawables.indexOf(selectedMarbleDrawable));

                        newState = DetermineDealerState.getInstance();

                    }

                }

                screen.draw(getDrawables(screen));

            }

        }

        return newState;

    }

    @Override
    public void handleResizeEvent(Screen screen, GameState gameState, int width, int height) {

        // check to see if we have a screen
        if (screen != null) {

            // get the drawables and draw them on the screen
            screen.draw(getDrawables(screen));

        }

    }

}
